package service

import (
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"
	"unicode/utf8"
	"wanfang-translation/internal/service/exception"
	"wanfang-translation/pkg/txtinput"

	"github.com/streadway/amqp"
)

/*
	翻译模块，分别创建中译英和英译中两个模块接口，两个接口分别位于独立的线程中
	两个翻译模块监听对应的消息队列，当有新的消息到达时，将消息内容进行翻译，然后将翻译结果存入对应的消息队列中。
*/

// note: TranslationMessage 定义翻译消息结构，该结构用于中译英和英译中输出队列，中译英监听队列是文本输入队列
type TranslationMessage struct {
	PaperID       string    `json:"paper_id"`
	SourceContent string    `json:"source_content"` // 源文本
	Content       string    `json:"content"`        // 翻译后的文本
	CreateTime    time.Time `json:"create_time"`
}

// Translator 定义翻译器接口
type Translator interface {
	Translate(content string, isCn2En bool) (string, error)
}

// TranslationService 翻译服务结构体
type TranslationService struct {
	conn             *amqp.Connection
	ch2en            *amqp.Channel
	en2ch            *amqp.Channel
	ch2enQueue       string // 中译英输入队列
	en2chQueue       string // 英译中输入队列
	ch2enResultQueue string // 中译英结果队列
	en2chResultQueue string // 英译中结果队列
	enCheckQueue     string // 英文查重队列
	chCheckQueue     string // 中文查重队列
	translator       Translator
	wg               sync.WaitGroup
}

// NewTranslationService 创建新的翻译服务
func NewTranslationService(config struct {
	MqURL            string
	Ch2enQueue       string
	En2chQueue       string
	Ch2enResultQueue string
	En2chResultQueue string
	EnCheckQueue     string
	ChCheckQueue     string
	Translator       Translator
}) (*TranslationService, error) {
	conn, err := amqp.Dial(config.MqURL)
	if err != nil {
		return nil, fmt.Errorf("连接MQ失败: %v", err)
	}

	ch2en, err := conn.Channel()
	if err != nil {
		return nil, fmt.Errorf("创建中译英通道失败: %v", err)
	}

	en2ch, err := conn.Channel()
	if err != nil {
		return nil, fmt.Errorf("创建英译中通道失败: %v", err)
	}

	return &TranslationService{
		conn:             conn,
		ch2en:            ch2en,
		en2ch:            en2ch,
		ch2enQueue:       config.Ch2enQueue,
		en2chQueue:       config.En2chQueue,
		ch2enResultQueue: config.Ch2enResultQueue,
		en2chResultQueue: config.En2chResultQueue,
		enCheckQueue:     config.EnCheckQueue,
		chCheckQueue:     config.ChCheckQueue,
		translator:       config.Translator,
	}, nil
}

// Start 启动翻译服务
func (s *TranslationService) Start(statisticsUtils *Statistics) error {
	// 启动中译英服务
	if err := s.startCh2En(statisticsUtils); err != nil {
		return fmt.Errorf("启动中译英服务失败: %v", err)
	}

	// 启动英译中服务
	if err := s.startEn2Ch(statisticsUtils); err != nil {
		return fmt.Errorf("启动英译中服务失败: %v", err)
	}

	return nil
}

// startCh2En 启动中译英服务
func (s *TranslationService) startCh2En(statisticsUtils *Statistics) error {
	// 设置每次只接收 10 条消息
	err := s.ch2en.Qos(10, 0, false)
	if err != nil {
		return fmt.Errorf("设置 Qos 失败: %v", err)
	}

	msgs, err := s.ch2en.Consume(
		s.ch2enQueue,
		"",
		false, // note: 关闭自动确认
		false,
		false,
		false,
		nil,
	)
	if err != nil {
		return err
	}

	s.wg.Add(1)
	go func() {
		defer s.wg.Done()
		for msg := range msgs {
			var transMsg txtinput.TxtInputMessage
			if err := json.Unmarshal(msg.Body, &transMsg); err != nil {
				msg.Nack(false, true)
				exception.LogError(exception.NewSystemError("解析消息失败" + err.Error()))
				return
			}

			// 将文件切分为段落
			paragraphs := SentenceSplit(transMsg.Content)
			exception.LogInfo(fmt.Sprintf("中译英接口完成段落切分, 切分后的段落数量: %d", len(paragraphs)))
			// 循环调用翻译接口
			translated := ""
			for _, paragraphsItem := range paragraphs {
				// 将段落进行切分，保证每个句子长度不超过500token，初步预估中文为200字，英文为500字
				sentence := SplitParagraphBySentence(paragraphsItem, 200)
				exception.LogInfo("中译英:开始调用翻译接口")
				for _, item := range sentence {
					// 统计翻译接口计算时间
					start := time.Now()
					t, err := s.translator.Translate(item, true)
					if err != nil {
						exception.LogError(exception.NewSystemError("翻译失败" + err.Error()))
						// 如果出现异常应该将消息重新放回队列
						msg.Nack(false, true)
						return
					}
					exception.LogInfo("中译英:子句子完成翻译")
					// 创建统计信息，添加到统计模块中
					statisticsUtils.AddStats("中译英翻译", &ModuleStats{
						TotalTime:      time.Since(start),
						TotalCount:     1,
						TotalCharCount: int64(utf8.RuneCountInString(item)),
					})
					translated += t
				}
				// 添加段落分隔符
				translated += "\n"
			}
			exception.LogInfo("中译英:翻译接口调用完成")
			// 如果发送的是空消息（包括去除收尾空格之后）那么直接返回
			if translated == "" || strings.TrimSpace(translated) == "" {
				continue
			}

			// 发送翻译结果
			result := TranslationMessage{
				PaperID:       transMsg.PaperID,
				SourceContent: transMsg.Content,
				Content:       translated,
				CreateTime:    time.Now(),
			}

			// 发送到中译英结果队列
			if err := s.publishCh2EnResult(result); err != nil {
				exception.LogError(exception.NewSystemError("发布中译英结果失败" + err.Error()))
				return
			}

			// 发送到英文查重队列
			if err := s.publishEnCheck(result); err != nil {
				exception.LogError(exception.NewSystemError("发布中译英查重失败" + err.Error()))
				return
			}

			// 确认消息
			msg.Ack(false)
		}
	}()

	return nil
}

// startEn2Ch 启动英译中服务
func (s *TranslationService) startEn2Ch(statisticsUtils *Statistics) error {
	// 设置每次只接收 10 条消息
	err := s.en2ch.Qos(10, 0, false)
	if err != nil {
		return fmt.Errorf("设置 Qos 失败: %v", err)
	}

	msgs, err := s.en2ch.Consume(
		s.en2chQueue,
		"",
		false, // note: 关闭自动确认
		false,
		false,
		false,
		nil,
	)
	if err != nil {
		return err
	}

	s.wg.Add(1)
	go func() {
		defer s.wg.Done()
		for msg := range msgs {
			var transMsg TranslationMessage
			if err := json.Unmarshal(msg.Body, &transMsg); err != nil {
				msg.Nack(false, true)
				exception.LogError(exception.NewSystemError("解析消息失败" + err.Error()))
				return
			}
			// 将文件切分为段落
			paragraphs := SentenceSplit(transMsg.Content)
			exception.LogInfo(fmt.Sprintf("英译中接口完成段落切分, 切分后的段落数量: %d", len(paragraphs)))
			translated := ""
			for _, paragraphsItem := range paragraphs {
				// 将段落进行切分，保证每个句子长度不超过500token，初步预估中文为200字，英文为500字
				sentence := SplitParagraphBySentence(paragraphsItem, 500)
				exception.LogInfo("英译中:开始调用翻译接口")
				// 循环调用翻译接口
				for _, item := range sentence {
					start := time.Now()
					t, err := s.translator.Translate(item, false)
					if err != nil {
						exception.LogError(exception.NewSystemError("翻译失败" + err.Error()))
						msg.Nack(false, true)
						return
					}
					// 创建统计信息，添加到统计模块中
					statisticsUtils.AddStats("英译中翻译", &ModuleStats{
						TotalTime:      time.Since(start),
						TotalCount:     1,
						TotalCharCount: int64(utf8.RuneCountInString(item)),
					})
					translated += t
					exception.LogInfo("英译中:子句子完成翻译")
				}
				// 添加段落分隔符
				translated += "\n"
			}
			exception.LogInfo("英译中:翻译接口调用完成")
			// 如果发送的是空消息（包括去除收尾空格之后）那么直接返回
			if translated == "" || strings.TrimSpace(translated) == "" {
				continue
			}

			// 发送翻译结果
			result := TranslationMessage{
				PaperID:       transMsg.PaperID,
				SourceContent: transMsg.Content,
				Content:       translated,
				CreateTime:    time.Now(),
			}

			if err := s.publishEn2ChResult(result); err != nil {
				exception.LogError(exception.NewSystemError("发布英译中结果失败" + err.Error()))
				return
			}

			// 发送到中文查重队列
			if err := s.publishChCheck(result); err != nil {
				exception.LogError(exception.NewSystemError("发布英译中查重失败" + err.Error()))
				return
			}

			// 确认消息
			msg.Ack(false)
		}
	}()

	return nil
}

// publishCh2EnResult 发布中译英结果
func (s *TranslationService) publishCh2EnResult(result TranslationMessage) error {
	body, err := json.Marshal(result)
	if err != nil {
		return err
	}

	return s.ch2en.Publish(
		"",
		s.ch2enResultQueue,
		false,
		false,
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})
}

// publishEn2ChResult 发布英译中结果
func (s *TranslationService) publishEn2ChResult(result TranslationMessage) error {
	body, err := json.Marshal(result)
	if err != nil {
		return err
	}

	return s.en2ch.Publish(
		"",
		s.en2chResultQueue,
		false,
		false,
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})
}

// publishEnCheck 发布英文查重结果
func (s *TranslationService) publishEnCheck(result TranslationMessage) error {
	body, err := json.Marshal(result)
	if err != nil {
		return err
	}
	return s.en2ch.Publish(
		"",
		s.enCheckQueue,
		false,
		false,
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})
}

// publishChCheck 发布中文查重结果
func (s *TranslationService) publishChCheck(result TranslationMessage) error {
	body, err := json.Marshal(result)
	if err != nil {
		return err
	}
	return s.en2ch.Publish(
		"",
		s.chCheckQueue,
		false,
		false,
		amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
		})
}

// Close 关闭服务
func (s *TranslationService) Close() {
	s.ch2en.Close()
	s.en2ch.Close()
	s.conn.Close()
	s.wg.Wait()
}
